package gang.org.springframework.framework.annotation;

import gang.org.springframework.framework.bean.GangAnnotatedBeanDefinition;
import gang.org.springframework.framework.bean.GangBeanDefinition;
import gang.org.springframework.framework.context.GangResourceLoaderAware;
import gang.org.springframework.framework.context.annotatation.GangScannedGenericBeanDefinition;
import gang.org.springframework.framework.core.io.GangResourcePatternResolver;
import gang.org.springframework.framework.core.io.support.GangResourcePatternUtils;
import gang.org.springframework.framework.core.type.classreading.GangCachingMetadataReaderFactory;
import gang.org.springframework.framework.core.type.classreading.GangMetadataReader;
import gang.org.springframework.framework.core.type.classreading.GangMetadataReaderFactory;
import gang.org.springframework.framework.io.GangResource;
import gang.org.springframework.framework.io.GangResourceLoader;
import gang.org.springframework.framework.util.GangClassUtils;

import java.util.EventListener;
import java.util.LinkedHashSet;
import java.util.Set;

/**
 * 类说明：gang.chen springboot深度实践
 *
 * @author gang.chen
 * @since 2022/5/22
 */
public class GangClassPathScanningCandidateComponentProvider implements GangResourceLoaderAware {

    public static final String default_resource_pattern = "**/*.class";

    private String resourcePattern = default_resource_pattern;

    /**
     * 初始化 resourcePatternResolver
     * 1) ComponentScanAnnotationParser.parse(...)
     * 2) ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(registry, useDefaultFilters, environment, resourceLoader);
     * 3) ClassPathScanningCandidateComponentProvider.setResourceLoader(...)
     * */
    private GangResourcePatternResolver resourcePatternResolver;


    private GangMetadataReaderFactory metadataReaderFactory;

    public Set<GangBeanDefinition> findCandidateComponents(String basePackage){
        //TODO
        if (false){
            return null;
        }else{
            return scanCandidateComponents(basePackage);
        }
    }

    private Set<GangBeanDefinition> scanCandidateComponents(String basePackage) {

        Set<GangBeanDefinition> candidates = new LinkedHashSet<>();

        String packageSearchPath =  GangResourcePatternResolver.CLASSPATH_URL_PREFIX + resolveBasePackage(basePackage) + '/' + this.resourcePattern;

        /**
         * GangResourcePatternResolver -> GangAnnotationConfigServletWebServerApplicationContext
         * */
        GangResourcePatternResolver resourcePatternResolver = getResourcePatternResolver();

        /**
         * 1 GenericApplicationContext.getResources
         * 2 AbstractApplicationContext.getResources
         * 3 PathMatchingResourcePatternResolver.getResources
         * 4 PathMatchingResourcePatternResolver.findAllClassPathResources
         * 5 PathMatchingResourcePatternResolver.doFindAllClassPathResources
         * */
        GangResource[] resources = resourcePatternResolver.getResources(packageSearchPath);

        for (GangResource resource : resources) {

            try{
                GangMetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
                if (isCandidateComponent(metadataReader)) {

                    GangScannedGenericBeanDefinition sbd = new GangScannedGenericBeanDefinition(metadataReader);
                    sbd.setResource(resource);

                    if (isCandidateComponent(sbd)) {
                        candidates.add(sbd);
                    }
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }

        return candidates;
    }

    public String resolveBasePackage(String basePackage){

        //TODO
        return GangClassUtils.convertClassNameToResourcePath(basePackage);

    }

    public GangResourcePatternResolver getResourcePatternResolver(){
        if (this.resourcePatternResolver==null) {

        }
        return this.resourcePatternResolver;
    }

    @Override
    public void setResourceLoader(GangResourceLoader resourceLoader) {
        this.resourcePatternResolver = GangResourcePatternUtils.getResourcePatternResolver(resourceLoader);
        this.metadataReaderFactory = new GangCachingMetadataReaderFactory(resourceLoader);
        //TODO
    }

    public final GangMetadataReaderFactory getMetadataReaderFactory(){
        if (this.metadataReaderFactory == null) {
            //TODO
        }
        return this.metadataReaderFactory;
    }

    protected boolean isCandidateComponent(GangMetadataReader metadataReader){
        return true;
    }

    protected boolean isCandidateComponent(GangAnnotatedBeanDefinition beanDefinition){
        return true;
    }
}
